import json
import os
import time
import traceback
import logging
import re
from downloadAudio import startThread
from concurrent.futures import ThreadPoolExecutor
import threading

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler("poetic_content.log",encoding="utf-8"),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger(__name__)

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException, NoSuchElementException, ElementClickInterceptedException

globalUrl = "https://www.gushiwen.cn"
json_file = 'tangshi_poems.json'

# 初始化WebDriver
def init_driver():
    """
    初始化selenium WebDriver
    :return: WebDriver实例
    """
    try:
        logger.info("开始初始化WebDriver...")
        # 使用Chrome浏览器，需要安装chromedriver
        # 可以根据需要更换为其他浏览器
        driver = webdriver.Chrome()
        # 设置隐式等待
        driver.implicitly_wait(10)
        logger.info("WebDriver初始化成功")
        
        # 在添加cookie前先访问网站首页
        driver.get(globalUrl)
        
        # 使用正确格式添加cookie
        driver.add_cookie({'name': 'gsw2017user', 'value': '7349997%7cC7E51F9E790EC184D4C6B2BAE0948585%7c2000%2f1%2f1%7c2025%2f9%2f22'})
        driver.add_cookie({'name': 'login', 'value': 'true'})
        
        return driver
    except Exception as e:
        logger.error(f"WebDriver初始化失败: {e}")
        logger.error(f"错误详情: {traceback.format_exc()}")
        return None

# 关闭WebDriver
def close_driver(driver):
    """
    关闭WebDriver实例和音频下载线程池
    :param driver: WebDriver实例
    """
    if driver:
        driver.quit()
        print("WebDriver已关闭")
        
        # 导入并关闭音频下载线程池
        # try:
        #     from downloadAudio import shutdown_executor
        #     shutdown_executor(wait=True)
        #     print("音频下载线程池已关闭")
        # except Exception as e:
        #     print(f"关闭线程池时发生错误: {e}")


def read_json_file(file_path):
    """
    读取JSON文件并返回Python对象
    :param file_path: JSON文件路径
    :return: 解析后的Python对象
    """
    logger.info(f"尝试读取JSON文件: {file_path}")
    # 检查文件是否存在
    if not os.path.exists(file_path):
        logger.error(f"错误: 文件 {file_path} 不存在")
        return None
    
    try:
        # 打开并读取JSON文件
        with open(file_path, 'r', encoding='utf-8') as f:
            data = json.load(f)
        logger.info(f"成功读取JSON文件: {file_path}")
        logger.info(f"JSON文件包含 {len(data)} 条记录")
        return data
    except json.JSONDecodeError as e:
        logger.error(f"JSON解析错误: {e}")
        logger.error(f"错误详情: {traceback.format_exc()}")
        return None
    except Exception as e:
        logger.error(f"读取文件时发生错误: {e}")
        logger.error(f"错误详情: {traceback.format_exc()}")
        return None


def get_content_by_type(driver, type, url, output_file=None):
    """
    根据类型和URL获取诗歌内容，并可选地写入JSON文件
    :param driver: WebDriver实例
    :param type: 诗歌类型
    :param url: 访问URL
    :param output_file: 输出的JSON文件路径，默认为None（不写入文件）
    :return: 获取的诗歌内容列表
    """
    try:
        print(f"正在获取 {type} 的内容，URL: {url}")
        # 使用selenium访问网页，设置页面加载超时为30秒
        driver.set_page_load_timeout(30)
        try:
            driver.get(url)
        except TimeoutException:
            logger.error(f"页面加载超时: {url}")
            # 尝试停止页面加载
            driver.execute_script("window.stop();")
            return []

        # 等待页面加载完成
        try:
            WebDriverWait(driver, 10).until(
                EC.presence_of_element_located((By.CSS_SELECTOR, '.left .sons .typecont'))
            )
        except TimeoutException:
            print(f"页面加载超时: {url}")
            return []

        # 根据页面结构提取诗歌内容
        poems = []
        poem_containers = driver.find_elements(By.CSS_SELECTOR, '.left .sons .typecont')
        print(f"当前获取当容器的长度为{len(poem_containers)}")

        # 所有分类
        all_poem_links = []
        all_audio_link = [] #所有音频资料
        for poem in poem_containers:
            bookMl_text = "未知分类"
            try:
                bookMl = poem.find_element(By.CLASS_NAME, 'bookMl')
                bookMl_text = bookMl.text.strip()
            except NoSuchElementException:
                bookMl_text = "未知分类"

            # 先收集所有链接信息，避免页面导航后DOM元素失效
            a_con = poem.find_elements(By.TAG_NAME, 'a')
            poem_links = []
            for a_item in a_con:
                title = a_item.text
                href = a_item.get_attribute("href")
                if title and href:
                    poem_links.append({'title': title, 'href': href})
                    all_audio_link.append({
                        'title': title,
                        'href': href
                    })
                else:
                    logger.warning("跳过无效的诗歌链接")
            all_poem_links.append({
                'bookMl': bookMl_text,
                'poem_links': poem_links
            })

        # 直接调用downloadAudioList函数，它内部已使用线程池
        downloadAudioList(all_audio_link)

        for item in all_poem_links[:2]:
            poem_children = []
            failed_poems = []  # 记录抓取失败的诗歌
            for link in item['poem_links']:
                title = link['title']
                href = link['href']
                
                try:
                    # 获取诗歌详细信息
                    poem_details = getPoemContent(driver, title, href)
                    
                    # 检查是否抓取成功
                    if poem_details is not None:
                        poem_children.append(poem_details)
                        print(f"成功添加诗歌 '{title}' 到列表")
                    # else:
                    #     error_msg = poem_details.get('error', '未知错误') if poem_details else '返回值为None'
                    #     failed_poems.append({'title': title, 'href': href, 'error': error_msg})
                    #     print(f"跳过失败的诗歌 '{title}': {error_msg}")
                except Exception as e:
                   failed_poems.append({'title': title, 'href': href, 'error': str(e)})
                   print(f"抓取诗歌 '{title}' 时发生异常: {str(e)}")
  
                # 打印并记录失败的诗歌信息
                if failed_poems:
                    fail_count = len(failed_poems)
                    logger.info(f"分类 '{bookMl_text}' 中有 {fail_count} 首诗歌抓取失败")
                    print(f"分类 '{bookMl_text}' 中有 {fail_count} 首诗歌抓取失败:")
                    for fail in failed_poems:
                        error_msg = f"- '{fail['title']}': {fail['error']} ({fail['href']})"
                        logger.warning(error_msg)
                        print(error_msg)
                


              
            # 添加数据到返回列表
            poems.append({
                'bookMl': item['bookMl'],
                'poem_children': poem_children,
                'failed_poems': failed_poems
            })

        # 统计成功和失败的诗歌总数
        total_success = sum(len(item['poem_children']) for item in poems)
        total_failed = sum(len(item.get('failed_poems', [])) for item in poems)
        print(f"成功获取 {total_success} 首{type}诗歌，{total_failed} 首抓取失败")

        # 如果指定了输出文件，则写入JSON
        if output_file:
            try:
                with open(output_file, 'w', encoding='utf-8') as f:
                    json.dump(poems, f, ensure_ascii=False, indent=2)
                print(f"成功将内容写入JSON文件: {output_file}")
            except Exception as e:
                print(f"写入JSON文件时发生错误: {e}")

        return poems

    except Exception as e:
        print(f"处理数据时发生错误: {e}")
        # 返回已收集的poems数据，而不是空列表
        return poems

  # 多线程下载音频（不阻塞主线程，主线程结束前等待子线程）
def downloadAudioList(all_audio_link):
    try:
        download_list = []
        for item in all_audio_link:
            try:
                title = item.get('title')
                href = item.get('href')
                if not title or not href:
                    logger.error(f"无效的音频链接数据: {item}")
                    continue
                id = extract_id(href)
                audio_url = f"https://ziyuan.guwendao.net/song/chenlang/{id}.mp3"
                filename = f"{title}.mp3"
                download_list.append({
                    'audio_url': audio_url,
                    'filename': filename,
                    'id': id,
                    'title': title
                })
            except Exception as e:
                logger.error(f"处理音频链接时发生错误: {e}, 链接数据: {item}")
        print(f"音频下载列表长度为：{len(download_list)}")
        if download_list:
            # 控制访问频率：每秒最多3个任务
            from downloadAudio import startup_download

            def submit_with_rate_limit(download_list, max_workers=10, rate_limit=3):
                with ThreadPoolExecutor(max_workers = max_workers) as executor:
                    executor.submit(startup_download,download_list)
               
            # 启动下载线程，不阻塞主线程
            def audio_download_thread():
                submit_with_rate_limit(download_list, max_workers=10, rate_limit=3)

            t = threading.Thread(target=audio_download_thread, daemon=True)
            t.start()
            # 主线程不等待此处，等主流程结束后再统一等待所有线程池任务

    except Exception as e:
        logger.error(f"下载音频列表时发生错误: {e}")
        # 记录错误但不抛出异常，确保其他数据处理不受影响

# 方法1.1：双重分割
def extract_id(url):
    # 先按"/"分割，取最后一部分
    filename = url.split("/")[-1]
    # 再按"_"和"."分割
    return filename.split("_")[1].split(".")[0]
# 获取诗句的具体内容
def getPoemContent(driver, title, href):
    # 提取诗歌内容
    author = ''
    dynasty = ''
    content = ''
    translation = ''
    appreciation = ''
    simpleAppreciation = '' # 简析

    print(f"正在获取诗歌 '{title}' 的详细内容，URL: {href}")
    # 使用selenium访问网页，设置页面加载超时为30秒
    driver.set_page_load_timeout(30)
    try:
        driver.get(href)
    except TimeoutException:
        logger.error(f"诗歌详情页加载超时: {href}")
        # 尝试停止页面加载
        driver.execute_script("window.stop();")
        return {'title': title, 'href': href, 'error': '页面加载超时'}

    
    # 等待页面加载完成
    try:
        # 增加超时时间到20秒，并等待多个可能的元素之一出现
        WebDriverWait(driver, 20).until(
            lambda d: EC.presence_of_element_located((By.CLASS_NAME, 'contson'))(d) or 
                        EC.presence_of_element_located((By.CLASS_NAME, 'cont'))(d) or 
                        EC.presence_of_element_located((By.TAG_NAME, 'body'))(d)
        )
        print(f"页面加载成功: {href}")
    except Exception as e:
        error_type = '超时' if isinstance(e, TimeoutException) else '错误'
        page_title = driver.title if isinstance(e, TimeoutException) else '未知'
        print(f"诗歌详情页加载{error_type}: {href}")
        if isinstance(e, TimeoutException):
            print(f"超时页面标题: {page_title}")
        return {'title': title, 'href': href, 'error': f'页面加载{error_type} ({title}: {str(e)})'}


   
    # 提取作者和朝代信息
    try:
        author_info = driver.find_element(By.CLASS_NAME, 'source')
        author_parts = author_info.text.strip().split('〔')
        author = author_parts[0].replace('作者：', '').strip() if len(author_parts) > 0 else '未知作者'
        dynasty = author_parts[1].replace('〕', '').strip() if len(author_parts) > 1 else '未知朝代'
    except NoSuchElementException:
        logger.info(f"未找到作者信息元素: {href}")


    try:
        content_div = driver.find_element(By.CLASS_NAME, 'contson')
        content = content_div.text
    except NoSuchElementException:
        logger.info(f"未找到诗歌内容元素: {href}")

    # 译文及注释
    translation_div = driver.find_element(By.CLASS_NAME,"contyishang")
    translation = translation_div.text.strip().replace('译文', '').strip()

    # 简析
    try:
        # 定位包含'简析'文本的h2元素，然后找到其父级class为'contyishang'的元素
        simple_appreciation_div = driver.find_element(By.XPATH, "//*[@class='contyishang'][.//h2/span[contains(., '简析')]]")
        simpleAppreciation = simple_appreciation_div.text.strip().replace('简析', '').strip()
    except NoSuchElementException:
        logger.warning(f"未找到简析元素: {href}")
        simpleAppreciation = ""
        
    # 赏析
    # 使用XPath 1.0兼容语法匹配id以'shangxi'开头且后跟数字的元素
    element_div = driver.find_element(By.XPATH,"//*[starts-with(@id, 'shangxi') and translate(@id, '0123456789', '') = 'shangxi']")

    try:
        expand_button = element_div.find_element(By.XPATH, ".//a[contains(text(), '展开阅读全文')]")
        div_id = element_div.get_attribute("id")
        logger.info(f"元素id: {div_id}")

        # 执行点击操作
        WebDriverWait(driver, 5).until(EC.element_to_be_clickable(expand_button))
        driver.execute_script("arguments[0].click();", expand_button)
        time.sleep(1)  # 等待内容加载
        logger.info("成功点击'展开阅读全文'按钮")

        id = "shangxiquan"+div_id.replace("shangxi","")
        element_div_quan = driver.find_element(By.ID,id)
        element_div_con =element_div_quan.find_element(By.CLASS_NAME,"contyishang")
        appreciation = element_div_con.text.strip().replace('赏析', '').strip()
    
    except NoSuchElementException as e:
        element_div_con =element_div.find_element(By.CLASS_NAME,"contyishang")
        appreciation = element_div_con.text.strip().replace('赏析', '').strip()


    
    # 构建诗歌详细信息字典，过滤空值
    poem_details = {
        'title': title,
        'author': author,
        'dynasty': dynasty,
        'content': content,
        'translation': translation
    }
    
    # 只添加非空的赏析和简析
    if appreciation.strip():  # 确保不是空字符串或只包含空白字符
        poem_details['appreciation'] = appreciation
    if simpleAppreciation.strip():  # 确保不是空字符串或只包含空白字符
        poem_details['simpleAppreciation'] = simpleAppreciation
    print(f"成功获取诗歌 '{title}' 的详细内容")
    return poem_details

def dispatchHandler(driver, h2_title, poem_details,href_id,block_index):
    pass
# 获取翻译内容
def getTranslationContent(s_item):
    return s_item.text
    
# 获取简析内容
def getSimpleAppreciationContent(s_item):
    return s_item.text
# 获取赏析内容
def getAppreciationContent(driver,href_id,s_item):
    if href_id:
       shangxiquan_ele = driver.find_element(By.ID,"shangxiquan"+href_id) 
       content = shangxiquan_ele.find_element(By.CLASS_NAME,"contyishang")
       return content.text
    else:
       return s_item.text

# 创作背景
def getCreationBackgroundContent(driver):
    pass

def main():
    """
    主函数，用于测试和运行诗歌内容处理
    """
    # 初始化WebDriver
    driver = init_driver()
    if not driver:
        print("无法初始化WebDriver，程序退出")
        exit(1)

    try:
        # 获取当前脚本所在目录
        current_dir = os.path.dirname(os.path.abspath(__file__))
        # 构建完整的JSON文件路径
        full_json_path = os.path.join(current_dir, '..', json_file)
        # 读取JSON文件
        poems_data = read_json_file(full_json_path)
        
        # 打印读取结果
        if poems_data is not None:
            print(f"数据类型: {type(poems_data)}")
            print(f"数据长度: {len(poems_data)}")
            
            # 创建一个列表存储所有分类的诗歌数据
            all_poems_data = []
            
            # 打印所有分类数据并获取内容
            print("\n所有分类数据:")
            for i, item in enumerate(poems_data[:1]):
                print(f"\n分类 {i+1}:{item['type']}")
                # 调用函数获取内容，但不写入单独文件
                poems = get_content_by_type(driver, item['type'], globalUrl+item['href'])
                # 将分类及其诗歌数据添加到总列表
                all_poems_data.append({
                    'category': item['type'],
                    'poems': poems
                })
                    
            
            # 将所有诗歌数据写入一个JSON文件
            output_file = os.path.join(current_dir, 'all_poems.json')
            try:
                with open(output_file, 'w', encoding='utf-8') as f:
                    json.dump(all_poems_data, f, ensure_ascii=False, indent=2)
                print(f"成功将所有诗歌数据写入JSON文件: {output_file}")
            except Exception as e:
                print(f"写入JSON文件时发生错误: {e}")
            
            # 统计分类数量
            categories = [item['type'] for item in poems_data]
            print(f"\n共包含 {len(categories)} 个诗歌分类")
            
    finally:
         # 关闭WebDriver
        close_driver(driver)
        print("准备调用 shutdown_executor")
        # 等待音频线程池任务全部完成再退出
        from downloadAudio import shutdown_executor
        print("等待所有音频下载任务完成...")
        shutdown_executor(wait=True)
        print("所有音频下载任务已完成")

# 如果直接运行该文件
if __name__ == '__main__':
    main()
